/** 
 * package game.
 * Contain main program and related GameState class
 */
package vn.com.fsoft.oopai.fsi.game;

import java.awt.Point;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;

import vn.com.fsoft.oopai.fsi.common.Common;

/**
 * Class Game State: Save current state of on going game.
 * @author OOPAI Group
 */
public class GameState {
    // Size of table (each table is a square of tableSize*tableSize)
	private int tableSize;
	// -1 if the cell is tool-breaker, 1->9 otherwise
	private int[][] status;
	// number of click
	private int[][] numClick;
	// store flag information of each cell
	private int[][] numFlag;
	/*
	 * remaingFlag indicate the remaining flag after user flag the cell.
	 * remaingFlag avoid the case that user always win in level 3 because in
	 * worst case, user can flag cell 36 times to always win
	 */
	private int remainingFlag = Common.NUMBER_FLAG_TO_WIN;
	/*
	 * In the init stage, numOfFlag is the maximum number of flag that allowed
	 * to use in the game to indicate tool breakers
	 */
	private int initializeNumOfFlag;

	public int getInitializeNumOfFlag() {
		return initializeNumOfFlag;
	}

	public void setInitializeNumOfFlag(int numOfFlag) {
		this.initializeNumOfFlag = numOfFlag;
	}

	/**
	 * Class constructor.
	 * Initiate table size and maximum number of flag allowed to
	 * use to indicate tool breakers
	 * @param tableSize : size of board to initiate
	 * @param defaultNumOfFlag : total number of flag allow to use
	 */
	public GameState(final int tableSize, final int initializeNumOfFlag) {
		this.tableSize = tableSize;
		setInitializeNumOfFlag(initializeNumOfFlag);
		status = new int[this.tableSize][this.tableSize];
		numClick = new int[this.tableSize][this.tableSize];
		numFlag = new int[this.tableSize][this.tableSize];
		initGameState();
	}

	public GameState(final int tableSize){
		this.tableSize = tableSize;
		status = new int[this.tableSize][this.tableSize];
		for (int i = 0; i < this.tableSize; i++)
			for (int j = 0; j < this.tableSize; j++) {
				status[i][j] = 0;
			}
	}
	/**
	 * Initiate tool breakers position.
	 */
	public void initGameState() {
		this.remainingFlag = this.initializeNumOfFlag;
		Random generator = new Random();
		Point temp;
		for (int i = 0; i < this.tableSize; i++)
			for (int j = 0; j < this.tableSize; j++) {
				status[i][j] = 0;
				numFlag[i][j] = 0;
				numClick[i][j] = 0;
			}
		Set<Point> set = new HashSet<Point>();
		do {
			temp = new Point();
			temp.x = generator.nextInt(this.tableSize);
			temp.y = generator.nextInt(this.tableSize);
			set.add(temp);
		} while (set.size() < 12);

		for (Point p : set) {
			this.status[p.x][p.y] = Common.TOOL_BREAKER;
			updateStatus(p.x, p.y);
		}
	}

	/**
	 * Use to update status of adjacent cells of tool-breaker
	 */
	public void updateStatus(int x, int y) {
		if (x > 0) {
			if (!isToolBreaker(this.status[x-1][y]))
				this.status[x - 1][y]++;
		}
		if (x < this.tableSize - 1) {
			if (!isToolBreaker(this.status[x+1][y]))
				this.status[x + 1][y]++;
		}
		if (y > 0) {
			if (!isToolBreaker(this.status[x][y-1]))
				this.status[x][y - 1]++;
		}
		if (y < this.tableSize - 1) {
			if (!isToolBreaker(this.status[x][y+1]))
				this.status[x][y + 1]++;
		}
		if (x > 0 && y > 0) {
			if (!isToolBreaker(this.status[x-1][y-1]))
				this.status[x - 1][y - 1]++;
		}
		if (x < this.tableSize - 1 && y < this.tableSize - 1) {
			if (!isToolBreaker(this.status[x + 1][y + 1]))
				this.status[x + 1][y + 1]++;
		}
		if (x > 0 && y < this.tableSize - 1) {
			if (!isToolBreaker(this.status[x - 1][y + 1]))
				this.status[x - 1][y + 1]++;
		}
		if (x < this.tableSize - 1 && y > 0) {
			if (!isToolBreaker(this.status[x + 1][y - 1]))
				this.status[x + 1][y - 1]++;
		}
	}

	/**
	 * Get total clicked viable space.
	 * @return total clicked viable space
	 */
	public final int getTotalViableSpaceClicked() {
		int count = 0;
		for (int i = 0; i < this.tableSize; i++) {
			for (int j = 0; j < this.tableSize; j++) {
				count += this.numClick[i][j];
			}
		}
		return count;
	}

	/**
	 * get method.
	 * 
	 * @return size of current table game
	 */

	public final int getTableSize() {
		return this.tableSize;
	}

	/**
	 * Increase the number of click of a cell.
	 * 
	 * @param x
	 *            : coordinate of the cell
	 * @param y
	 *            : coordinate of the cell
	 */
	public final void addNumClick(final int x, final int y) {
		this.numClick[x][y]++;
	}

	/**
	 * Get total number of click of a cell. Parameters x, y : coordinate of the
	 * cell
	 * 
	 * @param x
	 *            : coordinate of the cell
	 * @param y
	 *            : coordinate of the cell
	 * @return number of click count on a cell
	 */
	public final int getNumClick(final int x, final int y) {
		return this.numClick[x][y];
	}

	/**
	 * Check if a cell is tool breaker. Parameters x, y : coordinate of the cell
	 * 
	 * @param x
	 *            : coordinate of the cell
	 * @param y
	 *            : coordinate of the cell
	 * @return true if a cell is a tool breaker, false if not
	 */
	public final boolean isToolBreaker(final int cell) {
		return cell == Common.TOOL_BREAKER;
	}

	/**
	 * At level that allow to use flag. Get total number of correct flagged tool
	 * breakers
	 * 
	 * @return total number of correct flagged tool breakers
	 */
	public final int getTotalToolBreakerFlagged() {
		int count = 0;
		for (int i = 0; i < this.tableSize; i++) {
			for (int j = 0; j < this.tableSize; j++) {
				if (this.status[i][j] == -1) {
					count += this.numFlag[i][j];
				}
			}
		}
		return count;
	}

	/**
	 * Increase number of flag at a cell.
	 * 
	 * @param x
	 *            : coordinate of the cell
	 * @param y
	 *            : coordinate of the cell
	 */
	public final void addNumFlag(final int x, final int y) {
		this.numFlag[x][y]++;
	}

	/**
	 * Get number of flag at a cell.
	 * 
	 * @param x
	 *            : coordinate of the cell
	 * @param y
	 *            : coordinate of the cell
	 * @return total number of flag at a cell
	 */
	public final int getNumFlag(final int x, final int y) {
		return this.numFlag[x][y];
	}

	/**
	 * Decrease total number of remaining Flag each time a flag is used.
	 */
	public final void decreaseRemainingFlag() {
		this.remainingFlag--;
	}

	/**
	 * Increase total number of remaining flag if a flag is removed.
	 */
	public final void increaseRemainingFlag() {
		this.remainingFlag++;
	}

	/**
	 * Get total remaining flags.
	 * 
	 * @return total remaining flags
	 */
	public final int getRemainingFlag() {
		return this.remainingFlag;
	}

	/**
	 * Check if a cell at coordinate x, y is already flagged or not.
	 * 
	 * @param x
	 *            : coordinate of a cell
	 * @param y
	 *            : coordinate of a cell
	 * @return : true if a cell is already flagged, false if not
	 */
	public final boolean isFalgged(final int x, final int y) {
		return numFlag[x][y] != 0;
	}

	/**
	 * Return total score after game.
	 * 
	 * @return total score after game
	 */
	public final int getScore() {
		int temp = 0;
		for (int i = 0; i < this.tableSize; i++) {
			for (int j = 0; j < this.tableSize; j++) {
				temp += this.numClick[i][j] * this.status[i][j];
			}
		}
		return temp;
	}

	/**
	 * Remove flag at a cell with coordinate x,y.
	 * 
	 * @param x
	 *            : coordinate of a cell
	 * @param y
	 *            : coordinate of a cell
	 */
	public final void removeFlag(final int x, final int y) {
		this.numFlag[x][y] = 0;
		this.numClick[x][y] = 0;
	}

	/**
	 * Get current status of a cell with coordinate x,y.
	 * 
	 * @param x
	 *            : coordinate of a cell
	 * @param y
	 *            : coordinate of a cell
	 * @return -1 if cell is a tool breakers, 0 if not
	 */
	public final int getStatus(final int x, final int y) {
		return this.status[x][y];
	}
	
	public void setStatus(final int x, final int y, final int status){
		this.status[x][y] = status;
	}
}
